//package com.longshihan.lifecycler;
//
//import android.content.Context;
//import android.content.res.TypedArray;
//import android.support.annotation.ColorInt;
//import android.support.annotation.ColorRes;
//import android.support.annotation.Nullable;
//import android.support.annotation.VisibleForTesting;
//import android.support.v4.content.ContextCompat;
//import android.support.v4.view.NestedScrollingChild;
//import android.support.v4.view.NestedScrollingChildHelper;
//import android.support.v4.view.NestedScrollingParent;
//import android.support.v4.view.NestedScrollingParentHelper;
//import android.support.v4.view.ViewCompat;
//import android.util.AttributeSet;
//import android.util.DisplayMetrics;
//import android.util.Log;
//import android.view.MotionEvent;
//import android.view.View;
//import android.view.ViewConfiguration;
//import android.view.ViewGroup;
//import android.view.animation.Animation;
//import android.view.animation.Animation.AnimationListener;
//import android.view.animation.DecelerateInterpolator;
//import android.view.animation.LinearInterpolator;
//import android.view.animation.Transformation;
//import android.widget.AbsListView;
//
//import com.huazhu.utils.HZLog;
//
///**
// * Created by LIDONGDONG005 on 2018/3/23.
// */
//
//public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingParent,
//        NestedScrollingChild {
//    // Maps to ProgressBar.Large style
////    public static final int LARGE = MaterialProgressDrawable.LARGE;
//    // Maps to ProgressBar default style
////    public static final int DEFAULT = MaterialProgressDrawable.DEFAULT;
//
//    @VisibleForTesting
//    static final int CIRCLE_DIAMETER = 40;
//    @VisibleForTesting
////    static final int CIRCLE_DIAMETER_LARGE = 56;
//
//    private static final String LOG_TAG = SwipeRefreshLayout.class.getSimpleName();
//
//    private static final int MAX_ALPHA = 255;
////    private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA);
//
//    private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;
//    private static final int INVALID_POINTER = -1;
//    private static final float DRAG_RATE = .5f;
//
//    // Max amount of circle that can be filled by progress during swipe gesture,
//    // where 1.0 is a full circle
//    private static final float MAX_PROGRESS_ANGLE = 1.0f;
//
//    private static final int SCALE_DOWN_DURATION = 150;
//
////    private static final int ALPHA_ANIMATION_DURATION = 300;
//
//    private static final int ANIMATE_TO_TRIGGER_DURATION = 200;
//
//    private static final int ANIMATE_TO_START_DURATION = 200;
//
//    // Default background for the progress spinner
//    private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA;
//    // Default offset in dips from the top of the view to where the progress spinner should stop
//    private static final int DEFAULT_CIRCLE_TARGET = 64;
//
//    private View mTarget; // the target of the gesture
//    OnRefreshListener mListener;
//    boolean mRefreshing = false;
//    private int mTouchSlop;
//    private float mTotalDragDistance = -1;
//
//    // If nested scrolling is enabled, the total amount that needed to be
//    // consumed by this as the nested scrolling parent is used in place of the
//    // overscroll determined by MOVE events in the onTouch handler
//    private float mTotalUnconsumed;
//    private final NestedScrollingParentHelper mNestedScrollingParentHelper;
//    private final NestedScrollingChildHelper mNestedScrollingChildHelper;
//    private final int[] mParentScrollConsumed = new int[2];
//    private final int[] mParentOffsetInWindow = new int[2];
//    private boolean mNestedScrollInProgress;
//
//    private int mMediumAnimationDuration;
//    int mCurrentTargetOffsetTop;
//
//    private float mInitialMotionY;
//    private float mInitialDownY;
//    private boolean mIsBeingDragged;
//    private int mActivePointerId = INVALID_POINTER;
//    // Whether this item is scaled up rather than clipped
//    boolean mScale;
//
//    // Target is returning to its start offset because it was cancelled or a
//    // refresh was triggered.
//    private boolean mReturningToStart;  //返回到起始位置、或正在刷新
//    private final DecelerateInterpolator mDecelerateInterpolator;
//    private final LinearInterpolator mLinearInterpolator;
//    private static final int[] LAYOUT_ATTRS = new int[] {
//            android.R.attr.enabled
//    };
//
//    ProgressRingView mCircleView;
//    private int mCircleViewIndex = -1;
//
//    protected int mFrom;
//
//    float mStartingScale;
//
//    protected int mOriginalOffsetTop;
//
//    int mSpinnerOffsetEnd;
//
////    MaterialProgressDrawable mProgress;
//
//    private Animation mScaleAnimation;
//
//    private Animation mScaleDownAnimation;
//
////    private Animation mAlphaStartAnimation;
////
////    private Animation mAlphaMaxAnimation;
//
//    private Animation mScaleDownToStartAnimation;
//
//    boolean mNotify;
//
//    private int mCircleDiameter;
//
//    // Whether the client has set a custom starting position;
//    boolean mUsingCustomStart;
//
//    private OnChildScrollUpCallback mChildScrollUpCallback;
//
//    private AnimationListener mRefreshListener = new AnimationListener() {
//        @Override
//        public void onAnimationStart(Animation animation) {
//        }
//
//        @Override
//        public void onAnimationRepeat(Animation animation) {
//        }
//
//        @Override
//        public void onAnimationEnd(Animation animation) {
//            if (mRefreshing) {
//                // Make sure the progress view is fully visible
////                mProgress.setAlpha(MAX_ALPHA);
////                mProgress.start();             //开始旋转动画
//                mCircleView.start();             //开始旋转动画
//                if (mNotify) {
//                    if (mListener != null) {
//                        mListener.onRefresh();
//                    }
//                }
//                mCurrentTargetOffsetTop = mCircleView.getTop();
//            } else {
//                reset();
//            }
//        }
//    };
//
//    void reset() {
//        mCircleView.stop();  //停止旋转动画
//        mCircleView.clearAnimation();
////        mProgress.stop();
//        mCircleView.setVisibility(View.GONE);
//        setColorViewAlpha(MAX_ALPHA);
//        // Return the circle to its start position
//        if (mScale) {
//            setAnimationProgress(0 /* animation complete and view is hidden */);
//        } else {
//            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop);
////            Log.i("refresh", "偏移量reset  offset= "+(mOriginalOffsetTop - mCurrentTargetOffsetTop));
//        }
//        mCurrentTargetOffsetTop = mCircleView.getTop();
//    }
//
//    @Override
//    public void setEnabled(boolean enabled) {
//        super.setEnabled(enabled);
//        if (!enabled) {
//            reset();
//        }
//    }
//
//    @Override
//    protected void onDetachedFromWindow() {
//        super.onDetachedFromWindow();
//        reset();
//    }
//
//    private void setColorViewAlpha(int targetAlpha) {
////        mCircleView.getBackground().setAlpha(targetAlpha);
////        mProgress.setAlpha(targetAlpha);
//    }
//
//    /**
//     * The refresh indicator starting and resting position is always positioned
//     * near the top of the refreshing content. This position is a consistent
//     * location, but can be adjusted in either direction based on whether or not
//     * there is a toolbar or actionbar present.
//     * <p>
//     * <strong>Note:</strong> Calling this will reset the position of the refresh indicator to
//     * <code>start</code>.
//     * </p>
//     *
//     * @param scale Set to true if there is no view at a higher z-order than where the progress
//     *              spinner is set to appear. Setting it to true will cause indicator to be scaled
//     *              up rather than clipped.
//     * @param start The offset in pixels from the top of this view at which the
//     *              progress spinner should appear.
//     * @param end The offset in pixels from the top of this view at which the
//     *            progress spinner should come to rest after a successful swipe
//     *            gesture.
//     */
//    public void setProgressViewOffset(boolean scale, int start, int end) {
//        mScale = scale;
//        mOriginalOffsetTop = start;
//        mSpinnerOffsetEnd = end;
//        mUsingCustomStart = true;
//        reset();
//        mRefreshing = false;
//    }
//
//    /**
//     * @return The offset in pixels from the top of this view at which the progress spinner should
//     *         appear.
//     */
//    public int getProgressViewStartOffset() {
//        return mOriginalOffsetTop;
//    }
//
//    /**
//     * @return The offset in pixels from the top of this view at which the progress spinner should
//     *         come to rest after a successful swipe gesture.
//     */
//    public int getProgressViewEndOffset() {
//        return mSpinnerOffsetEnd;
//    }
//
//    /**
//     * The refresh indicator resting position is always positioned near the top
//     * of the refreshing content. This position is a consistent location, but
//     * can be adjusted in either direction based on whether or not there is a
//     * toolbar or actionbar present.
//     *
//     * @param scale Set to true if there is no view at a higher z-order than where the progress
//     *              spinner is set to appear. Setting it to true will cause indicator to be scaled
//     *              up rather than clipped.
//     * @param end The offset in pixels from the top of this view at which the
//     *            progress spinner should come to rest after a successful swipe
//     *            gesture.
//     */
////    public void setProgressViewEndTarget(boolean scale, int end) {
////        mSpinnerOffsetEnd = end;
////        mScale = scale;
////        mCircleView.invalidate();
////    }
//
//    /**
//     * One of DEFAULT, or LARGE.
//     */
////    public void setSize(int size) {
////        if (size != MaterialProgressDrawable.LARGE && size != MaterialProgressDrawable.DEFAULT) {
////            return;
////        }
////        final DisplayMetrics metrics = getResources().getDisplayMetrics();
////        if (size == MaterialProgressDrawable.LARGE) {
////            mCircleDiameter = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);
////        } else {
////            mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density);
////        }
////        // force the bounds of the progress circle inside the circle view to
////        // update by setting it to null before updating its size and then
////        // re-setting it
////        mCircleView.setImageDrawable(null);
////        mProgress.updateSizes(size);
////        mCircleView.setImageDrawable(mProgress);
////    }
//
//    /**
//     * Simple constructor to use when creating a SwipeRefreshLayout from code.
//     *
//     * @param context
//     */
//    public SwipeRefreshLayout(Context context) {
//        this(context, null);
//    }
//
//    /**
//     * Constructor that is called when inflating SwipeRefreshLayout from XML.
//     *
//     * @param context
//     * @param attrs
//     */
//    public SwipeRefreshLayout(Context context, AttributeSet attrs) {
//        super(context, attrs);
//
//        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
//
//        mMediumAnimationDuration = getResources().getInteger(
//                android.R.integer.config_mediumAnimTime);
//
//        setWillNotDraw(false);
//        mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
//        mLinearInterpolator = new LinearInterpolator();
//
//        final DisplayMetrics metrics = getResources().getDisplayMetrics();
//        mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density);
//
//        createProgressView();
//        ViewCompat.setChildrenDrawingOrderEnabled(this, true);
//        // the absolute offset has to take into account that the circle starts at an offset
//        mSpinnerOffsetEnd = (int) (DEFAULT_CIRCLE_TARGET * metrics.density);
//        mTotalDragDistance = mSpinnerOffsetEnd;
//        mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
//
//        mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
//        setNestedScrollingEnabled(true);
//
//        mOriginalOffsetTop = mCurrentTargetOffsetTop = -mCircleDiameter;
//        moveToStart(1.0f);
//
//        final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
//        setEnabled(a.getBoolean(0, true));
//        a.recycle();
//    }
//
//    @Override
//    protected int getChildDrawingOrder(int childCount, int i) {
//        if (mCircleViewIndex < 0) {
//            return i;
//        } else if (i == childCount - 1) {
//            // Draw the selected child last
//            return mCircleViewIndex;
//        } else if (i >= mCircleViewIndex) {
//            // Move the children after the selected child earlier one
//            return i + 1;
//        } else {
//            // Keep the children before the selected child the same
//            return i;
//        }
//    }
//
//    private void createProgressView() {
//        mCircleView = new ProgressRingView(getContext(), CIRCLE_BG_LIGHT);
////        mProgress = new MaterialProgressDrawable(getContext(), this);
////        mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
////        mCircleView.setImageDrawable(mProgress);
//        mCircleView.setVisibility(View.GONE);
//        addView(mCircleView);
//    }
//
//    /**
//     * Set the listener to be notified when a refresh is triggered via the swipe
//     * gesture.
//     */
//    public void setOnRefreshListener(OnRefreshListener listener) {
//        mListener = listener;
//    }
//
//    /**
//     * Notify the widget that refresh state has changed. Do not call this when
//     * refresh is triggered by a swipe gesture.
//     *
//     * @param refreshing Whether or not the view should show refresh progress.
//     */
//    public void setRefreshing(boolean refreshing) {
//        if (refreshing && mRefreshing != refreshing) {
//            // scale and show
//            mRefreshing = refreshing;
//            int endTarget = 0;
//            if (!mUsingCustomStart) {
//                endTarget = mSpinnerOffsetEnd + mOriginalOffsetTop;
//            } else {
//                endTarget = mSpinnerOffsetEnd;
//            }
//            setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop);
////            Log.i("refresh", "偏移量setRefreshing  offset= "+(endTarget - mCurrentTargetOffsetTop));
//            mNotify = false;
//            startScaleUpAnimation(mRefreshListener); //放大动画
//        } else {
//            setRefreshing(refreshing, false /* notify */);
//        }
//    }
//    /**启动放大动画*/
//    private void startScaleUpAnimation(AnimationListener listener) {
//        mCircleView.setVisibility(View.VISIBLE);
//        if (android.os.Build.VERSION.SDK_INT >= 11) {
//            // Pre API 11, alpha is used in place of scale up to show the
//            // progress circle appearing.
//            // Don't adjust the alpha during appearance otherwise.
////            mProgress.setAlpha(MAX_ALPHA);
//        }
//        mScaleAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                setAnimationProgress(interpolatedTime);
//            }
//        };
//        mScaleAnimation.setDuration(mMediumAnimationDuration);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mScaleAnimation);
//    }
//
//    /**
//     * Pre API 11, this does an alpha animation.
//     * @param progress
//     */
//    void setAnimationProgress(float progress) {
//        mCircleView.setScaleX(progress);
//        mCircleView.setScaleY(progress);
//    }
//    /** 控制刷新  refreshing 是否刷新， notify   */
//    private void setRefreshing(boolean refreshing, final boolean notify) {
//        if (mRefreshing != refreshing) {
//            mNotify = notify;
//            ensureTarget();
//            mRefreshing = refreshing;
//            if (mRefreshing) {
//                animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener);  //矫正view的位置
//            } else {
////                startScaleDownAnimation(mRefreshListener);
//                animateOffsetToStartPosition(mCurrentTargetOffsetTop, mRefreshListener, 500);
//            }
//        }
//    }
//    /** 启动缩小动画 */
//    void startScaleDownAnimation(AnimationListener listener) {
//        mScaleDownAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                setAnimationProgress(1 - interpolatedTime);
//            }
//        };
//        mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION);
//        mCircleView.clearAnimation();
//        mCircleView.setAnimationListener(listener);
//        mCircleView.startAnimation(mScaleDownAnimation);
//    }
//    /** 启动mProgress透明度变化开始（mProgress当前透明度到加载中的透明度STARTING_PROGRESS_ALPHA）动画 */
//    private void startProgressAlphaStartAnimation() {
////        mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA);
//    }
//    /** 启动mProgress透明度变化最大值（mProgress当前透明度到不透明255）动画 */
//    private void startProgressAlphaMaxAnimation() {
////        mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA);
//    }
//    /** 启动mProgress透明度变化动画实现 */
//    private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) {
//        Animation alpha = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
////                mProgress.setAlpha(
////                        (int) (startingAlpha + ((endingAlpha - startingAlpha) * interpolatedTime)));
//            }
//        };
////        alpha.setDuration(ALPHA_ANIMATION_DURATION);
//        // Clear out the previous animation listeners.
//        mCircleView.setAnimationListener(null);
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(alpha);
//        return alpha;
//    }
//
//    /**
//     * 设置圆的背景颜色 颜色resID
//     * @deprecated Use {@link #setProgressBackgroundColorSchemeResource(int)}
//     */
//    @Deprecated
//    public void setProgressBackgroundColor(int colorRes) {
//        setProgressBackgroundColorSchemeResource(colorRes);
//    }
//
//    /**
//     * 设置圆的背景颜色 重载方法  颜色resID
//     * Set the background color of the progress spinner disc.
//     *
//     * @param colorRes Resource id of the color.
//     */
//    public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
//        setProgressBackgroundColorSchemeColor(ContextCompat.getColor(getContext(), colorRes));
//    }
//
//    /**
//     * 设置圆的背景颜色  颜色resID
//     * Set the background color of the progress spinner disc.
//     *
//     * @param color
//     */
//    public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {
//        mCircleView.setBackgroundColor(color);
////        mProgress.setBackgroundColor(color);
//    }
//
//    /**
//     * 设置进度一组颜色值
//     * @deprecated Use {@link #setColorSchemeResources(int...)}
//     */
////    @Deprecated
////    public void setColorScheme(@ColorInt int... colors) {
////        setColorSchemeResources(colors);
////    }
//
//    /**
//     * 设置进度一组颜色值
//     * Set the color resources used in the progress animation from color resources.
//     * The first color will also be the color of the bar that grows in response
//     * to a user swipe gesture.
//     *
//     * @param colorResIds
//     */
////    public void setColorSchemeResources(@ColorRes int... colorResIds) {
////        final Context context = getContext();
////        int[] colorRes = new int[colorResIds.length];
////        for (int i = 0; i < colorResIds.length; i++) {
////            colorRes[i] = ContextCompat.getColor(context, colorResIds[i]);
////        }
////        setColorSchemeColors(colorRes);
////    }
//
//    /**
//     * 设置进度一组颜色值
//     * Set the colors used in the progress animation. The first
//     * color will also be the color of the bar that grows in response to a user
//     * swipe gesture.
//     *
//     * @param colors
//     */
////    public void setColorSchemeColors(@ColorInt int... colors) {
////        ensureTarget();
////        mProgress.setColorSchemeColors(colors);
////    }
//
//    /**
//     * @return Whether the SwipeRefreshWidget is actively showing refresh
//     *         progress.
//     */
//    public boolean isRefreshing() {
//        return mRefreshing;
//    }
//    /**保障mTarget的值*/
//    private void ensureTarget() {
//        // Don't bother getting the parent height if the parent hasn't been laid
//        // out yet.
//        if (mTarget == null) {
//            for (int i = 0; i < getChildCount(); i++) {
//                View child = getChildAt(i);
//                if (!child.equals(mCircleView)) {
//                    mTarget = child;
//                    break;
//                }
//            }
//        }
//    }
//
//    /**
//     * Set the distance to trigger a sync in dips
//     *
//     * @param distance
//     */
//    public void setDistanceToTriggerSync(int distance) {
//        mTotalDragDistance = distance;
//    }
//    /**
//     * 布局  先处理mTarget的布局，然后处理 圆 的布局
//     * */
//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        final int width = getMeasuredWidth();
//        final int height = getMeasuredHeight();
//        if (getChildCount() == 0) {
//            return;
//        }
//        if (mTarget == null) {
//            ensureTarget();
//        }
//        if (mTarget == null) {
//            return;
//        }
//        final View child = mTarget;
//        final int childLeft = getPaddingLeft();
//        final int childTop = getPaddingTop();
//        final int childWidth = width - getPaddingLeft() - getPaddingRight();
//        final int childHeight = height - getPaddingTop() - getPaddingBottom();
//        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
//        int circleWidth = mCircleView.getMeasuredWidth();
//        int circleHeight = mCircleView.getMeasuredHeight();
//        mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop,
//                (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight);
//    }
//
//    @Override
//    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        if (mTarget == null) {
//            ensureTarget();
//        }
//        if (mTarget == null) {
//            return;
//        }
//        mTarget.measure(MeasureSpec.makeMeasureSpec(
//                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
//                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
//                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
//        mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY),
//                MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY));
//        mCircleViewIndex = -1;
//        // Get the index of the circleview.
//        for (int index = 0; index < getChildCount(); index++) {  //更新 圆 的index
//            if (getChildAt(index) == mCircleView) {
//                mCircleViewIndex = index;
//                break;
//            }
//        }
//    }
//
//    /**
//     * Get the diameter of the progress circle that is displayed as part of the
//     * swipe to refresh layout.
//     *
//     * @return Diameter in pixels of the progress circle view.
//     */
////    public int getProgressCircleDiameter() {
////        return mCircleDiameter;
////    }
//
//    /**
//     * mTarget 能否向上滚
//     * @return Whether it is possible for the child view of this layout to
//     *         scroll up. Override this if the child view is a custom view.
//     */
//    public boolean canChildScrollUp() {
//        if (mChildScrollUpCallback != null) {
//            return mChildScrollUpCallback.canChildScrollUp(this, mTarget);
//        }
//        return ViewCompat.canScrollVertically(mTarget, -1);
//    }
//
//    /**
//     * Set a callback to override {@link SwipeRefreshLayout#canChildScrollUp()} method. Non-null
//     * callback will return the value provided by the callback and ignore all internal logic.
//     * @param callback Callback that should be called when canChildScrollUp() is called.
//     */
//    public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) {
//        mChildScrollUpCallback = callback;
//    }
//
//    @Override
//    public boolean onInterceptTouchEvent(MotionEvent ev) {
//        ensureTarget();
//
//        final int action = ev.getActionMasked();
//        int pointerIndex;
//
//        if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {  //？？？？
//            mReturningToStart = false;
//        }
//        //以下情况不处理事件:控件不可用、控件状态返回初始位置时、正在刷新时、子view可能向上滚时、正在嵌套滚动时
//        if (!isEnabled() || mReturningToStart || canChildScrollUp()
//                || mRefreshing || mNestedScrollInProgress) {
//            // Fail fast if we're not in a state where a swipe is possible
//            return false;
//        }
//
//        switch (action) {
//            case MotionEvent.ACTION_DOWN:
//                setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop()); //矫正top值
////                Log.i("refresh", "偏移量ACTION_DOWN  offset= "+(mOriginalOffsetTop - mCircleView.getTop()));
//                mActivePointerId = ev.getPointerId(0);
//                mIsBeingDragged = false;
//
//                pointerIndex = ev.findPointerIndex(mActivePointerId);
//                if (pointerIndex < 0) { //校验手指按下的事件point是否有效
//                    return false;
//                }
//                mInitialDownY = ev.getY(pointerIndex);  //记录按下时的Y值
//                break;
//
//            case MotionEvent.ACTION_MOVE:
//                if (mActivePointerId == INVALID_POINTER) { //移动时，校验按下的那根手指事件point是否有效
//                    HZLog.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
//                    return false;
//                }
//
//                pointerIndex = ev.findPointerIndex(mActivePointerId);
//                if (pointerIndex < 0) { //校验按下的那根手指事件point是否有效
//                    return false;
//                }
//                final float y = ev.getY(pointerIndex);
//                //开始拖拽准备，并打开事件拦截标志  mInitialMotionY = mInitialDownY + mTouchSlop; mIsBeingDragged = true;
//                startDragging(y);
//                break;
//
//            case MotionEvent.ACTION_POINTER_UP:
//                onSecondaryPointerUp(ev);  //当有手指抬起的时候，如果正是按下的那根手指，则更新按下的手指mActivePointerId为下一根
//                break;
//
//            case MotionEvent.ACTION_UP:
//            case MotionEvent.ACTION_CANCEL:
//                mIsBeingDragged = false;
//                mActivePointerId = INVALID_POINTER;
//                break;
//        }
//
//        return mIsBeingDragged;   //在 startDragging（）方法中将该值值为true了
//    }
//
//    @Override
//    public void requestDisallowInterceptTouchEvent(boolean b) {
//        // if this is a List < L or another view that doesn't support nested
//        // scrolling, ignore this request so that the vertical scroll event
//        // isn't stolen
//        if ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView)
//                || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget))) {
//            // Nope.
//        } else {
//            super.requestDisallowInterceptTouchEvent(b);
//        }
//    }
//
//    // NestedScrollingParent
//
//    @Override
//    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
//        return isEnabled() && !mReturningToStart && !mRefreshing
//                && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
//    }
//
//    @Override
//    public void onNestedScrollAccepted(View child, View target, int axes) {
//        // Reset the counter of how much leftover scroll needs to be consumed.
//        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
//        // Dispatch up to the nested parent
//        startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
//        mTotalUnconsumed = 0;
//        mNestedScrollInProgress = true;
//    }
//
//    @Override
//    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
//        // If we are in the middle of consuming, a scroll, then we want to move the spinner back up
//        // before allowing the list to scroll
//        if (dy > 0 && mTotalUnconsumed > 0) {
//            if (dy > mTotalUnconsumed) {
//                consumed[1] = dy - (int) mTotalUnconsumed;
//                mTotalUnconsumed = 0;
//            } else {
//                mTotalUnconsumed -= dy;
//                consumed[1] = dy;
//            }
//            moveSpinner(mTotalUnconsumed);
//        }
//
//        // If a client layout is using a custom start position for the circle
//        // view, they mean to hide it again before scrolling the child view
//        // If we get back to mTotalUnconsumed == 0 and there is more to go, hide
//        // the circle so it isn't exposed if its blocking content is moved
//        if (mUsingCustomStart && dy > 0 && mTotalUnconsumed == 0
//                && Math.abs(dy - consumed[1]) > 0) {
//            mCircleView.setVisibility(View.GONE);
//        }
//
//        // Now let our nested parent consume the leftovers
//        final int[] parentConsumed = mParentScrollConsumed;
//        if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
//            consumed[0] += parentConsumed[0];
//            consumed[1] += parentConsumed[1];
//        }
//    }
//
//    @Override
//    public int getNestedScrollAxes() {
//        return mNestedScrollingParentHelper.getNestedScrollAxes();
//    }
//
//    @Override
//    public void onStopNestedScroll(View target) {
//        mNestedScrollingParentHelper.onStopNestedScroll(target);
//        mNestedScrollInProgress = false;
//        // Finish the spinner for nested scrolling if we ever consumed any
//        // unconsumed nested scroll
//        if (mTotalUnconsumed > 0) {
//            finishSpinner(mTotalUnconsumed);
//            mTotalUnconsumed = 0;
//        }
//        // Dispatch up our nested parent
//        stopNestedScroll();
//    }
//
//    @Override
//    public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
//                               final int dxUnconsumed, final int dyUnconsumed) {
//        // Dispatch up to the nested parent first
//        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
//                mParentOffsetInWindow);
//
//        // This is a bit of a hack. Nested scrolling works from the bottom up, and as we are
//        // sometimes between two nested scrolling views, we need a way to be able to know when any
//        // nested scrolling parent has stopped handling events. We do that by using the
//        // 'offset in window 'functionality to see if we have been moved from the event.
//        // This is a decent indication of whether we should take over the event stream or not.
//        final int dy = dyUnconsumed + mParentOffsetInWindow[1];
//        if (dy < 0 && !canChildScrollUp()) {
//            mTotalUnconsumed += Math.abs(dy);
//            moveSpinner(mTotalUnconsumed);
//        }
//    }
//
//    // NestedScrollingChild
//
//    @Override
//    public void setNestedScrollingEnabled(boolean enabled) {
//        mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
//    }
//
//    @Override
//    public boolean isNestedScrollingEnabled() {
//        return mNestedScrollingChildHelper.isNestedScrollingEnabled();
//    }
//
//    @Override
//    public boolean startNestedScroll(int axes) {
//        return mNestedScrollingChildHelper.startNestedScroll(axes);
//    }
//
//    @Override
//    public void stopNestedScroll() {
//        mNestedScrollingChildHelper.stopNestedScroll();
//    }
//
//    @Override
//    public boolean hasNestedScrollingParent() {
//        return mNestedScrollingChildHelper.hasNestedScrollingParent();
//    }
//
//    @Override
//    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
//                                        int dyUnconsumed, int[] offsetInWindow) {
//        return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
//                dxUnconsumed, dyUnconsumed, offsetInWindow);
//    }
//
//    @Override
//    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
//        return mNestedScrollingChildHelper.dispatchNestedPreScroll(
//                dx, dy, consumed, offsetInWindow);
//    }
//
//    @Override
//    public boolean onNestedPreFling(View target, float velocityX,
//                                    float velocityY) {
//        return dispatchNestedPreFling(velocityX, velocityY);
//    }
//
//    @Override
//    public boolean onNestedFling(View target, float velocityX, float velocityY,
//                                 boolean consumed) {
//        return dispatchNestedFling(velocityX, velocityY, consumed);
//    }
//
//    @Override
//    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
//        return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
//    }
//
//    @Override
//    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
//        return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
//    }
//
//    private boolean isAnimationRunning(Animation animation) {
//        return animation != null && animation.hasStarted() && !animation.hasEnded();
//    }
//
//    private void moveSpinner(float overscrollTop) {
////        mProgress.showArrow(false);
////        overscrollTop = overscrollTop>mTotalDragDistance?mTotalDragDistance:overscrollTop;
//        float originalDragPercent = overscrollTop / mTotalDragDistance;  //原始拖拽百分比
//
//        float dragPercent = Math.min(1f, Math.abs(originalDragPercent));  //拖拽百分比不大于1
//        float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3; //矫正后的百分比  添加偏移量
//        float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;  //当前滚动量与最大可滚动量的差值
//        float slingshotDist = mUsingCustomStart ? mSpinnerOffsetEnd - mOriginalOffsetTop
//                : mSpinnerOffsetEnd;
//        float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2)
//                / slingshotDist);
//        float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
//                (tensionSlingshotPercent / 4), 2)) * 2f;
//        float extraMove = (slingshotDist) * tensionPercent * 2;
//
//        int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);
//        // where 1.0f is a full circle
//        if (mCircleView.getVisibility() != View.VISIBLE) {
//            mCircleView.setVisibility(View.VISIBLE);
//        }
//        if (!mScale) {  //恢复进度view的大小
//            mCircleView.setScaleX(1f);
//            mCircleView.setScaleY(1f);
//        }
//
//        if (mScale) { //缩放动画 设置X Y缩放
//            setAnimationProgress(Math.min(1f, overscrollTop / mTotalDragDistance));
//        }
////        if (overscrollTop < mTotalDragDistance) {
////            if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA
////                    && !isAnimationRunning(mAlphaStartAnimation)) {
////                // Animate the alpha
////                startProgressAlphaStartAnimation();  //渐变动画
////            }
////        } else {
////            if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) {
////                // Animate the alpha
////                startProgressAlphaMaxAnimation();
////            }
////        }
////        float strokeStart = adjustedPercent * .8f;
////        Log.i("refresh1", "滑动 adjustedPercent= "+ adjustedPercent+"    dragPercent= "+dragPercent + "   originalDragPercent= "+originalDragPercent);
//        mCircleView.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, adjustedPercent));
////        mProgress.setArrowScale(Math.min(1f, adjustedPercent));
//
////        float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
////        mProgress.setProgressRotation(rotation);
////        if(originalDragPercent < 1.1 ){
//        setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop);
////            if (mListener != null) {
////                mListener.onOffset(targetY - mCurrentTargetOffsetTop, false, (int)mTotalDragDistance);
////                Log.i("refresh", "偏移量moving  dragPercent= "+dragPercent+"  targetY="+targetY+"  mCurrentTargetOffsetTop="+mCurrentTargetOffsetTop);
////            }
////        }
//    }
//    /** 手指抬起时，处理刷新 or 回弹 */
//    private void finishSpinner(float overscrollTop) {
//
//        if (overscrollTop > mTotalDragDistance) {  //拖拽达到最大可拖拽距离，则开始刷新
//            setRefreshing(true, true /* notify */);
//        } else {    //没有达到刷新的状态，则回弹
//            // cancel refresh
//            mRefreshing = false;
//            mCircleView.setStartEndTrim(0f, 0f);  //设置进度环的起始和结束角度
////            Log.i("refresh", "回弹 mScale= "+ mScale);
//            AnimationListener listener = null;
////            if (!mScale) {  //没有缩放时，初始化缩放
////                listener = new Animation.AnimationListener() {
////
////                    @Override
////                    public void onAnimationStart(Animation animation) {
////                    }
////
////                    @Override
////                    public void onAnimationEnd(Animation animation) {
//////                        if (!mScale) {
//////                            startScaleDownAnimation(null);
//////                        }
////                    }
////
////                    @Override
////                    public void onAnimationRepeat(Animation animation) {
////                    }
////
////                };
////            }
//            animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener, ANIMATE_TO_START_DURATION);
////            mProgress.showArrow(false);
//        }
//        if(mListener != null){
//            mListener.onActionUp();
//        }
//    }
//
//    @Override
//    public boolean onTouchEvent(MotionEvent ev) {
//        final int action = ev.getActionMasked();
//        int pointerIndex = -1;
//
//        if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
//            mReturningToStart = false;
//        }
//        //不处理事件的条件，同onInterceptTouchEvent()
//        if (!isEnabled() || mReturningToStart || canChildScrollUp()
//                || mRefreshing || mNestedScrollInProgress) {
//            // Fail fast if we're not in a state where a swipe is possible
//            return false;
//        }
//
//        switch (action) {
//            case MotionEvent.ACTION_DOWN:
//                mActivePointerId = ev.getPointerId(0);
//                mIsBeingDragged = false;
//                break;
//
//            case MotionEvent.ACTION_MOVE: {
//                pointerIndex = ev.findPointerIndex(mActivePointerId);
//                if (pointerIndex < 0) {
//                    HZLog.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
//                    return false;
//                }
//
//                final float y = ev.getY(pointerIndex);
//                startDragging(y);
//
//                if (mIsBeingDragged) {
//                    final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
//                    if (overscrollTop > 0) {
//                        moveSpinner(overscrollTop);  //处理滑动中的效果
//                    } else {
//                        return false;
//                    }
//                }
//                break;
//            }
//            case MotionEvent.ACTION_POINTER_DOWN: {
//                pointerIndex = ev.getActionIndex();
//                if (pointerIndex < 0) {
//                    Log.e(LOG_TAG,
//                            "Got ACTION_POINTER_DOWN event but have an invalid action index.");
//                    return false;
//                }
//                mActivePointerId = ev.getPointerId(pointerIndex);
//                break;
//            }
//
//            case MotionEvent.ACTION_POINTER_UP:
//                onSecondaryPointerUp(ev);
//                break;
//
//            case MotionEvent.ACTION_UP: {
//                pointerIndex = ev.findPointerIndex(mActivePointerId);
//                if (pointerIndex < 0) {
//                    Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
//                    return false;
//                }
//
//                if (mIsBeingDragged) {
//                    final float y = ev.getY(pointerIndex);
//                    final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
//                    mIsBeingDragged = false;
//                    finishSpinner(overscrollTop);   //抬起手势，处理拖拽回弹  overscrollTop：滚动值
//                }
//                mActivePointerId = INVALID_POINTER;
//                return false;
//            }
//            case MotionEvent.ACTION_CANCEL:
//                return false;
//        }
//
//        return true;
//    }
//    /** 开始拖拽准备，调整进度的透明度为STARTING_PROGRESS_ALPHA */
//    private void startDragging(float y) {
//        final float yDiff = y - mInitialDownY;
//        if (yDiff > mTouchSlop && !mIsBeingDragged) {
//            mInitialMotionY = mInitialDownY + mTouchSlop;
//            mIsBeingDragged = true;
////            mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
//        }
//    }
//    /** 动画矫正位置  回弹到加载动画的位置 */
//    private void animateOffsetToCorrectPosition(int from, AnimationListener listener) {
//        mFrom = from;
//        mAnimateToCorrectPosition.reset();
//        mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION);
//        mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mAnimateToCorrectPosition);
//    }
//
//    private void animateOffsetToStartPosition(int from, AnimationListener listener, int duration) {
//        if (mScale) {
//            // Scale the item back down
//            startScaleDownReturnToStartAnimation(from, listener);
//        } else {
//            mFrom = from;
//            mAnimateToStartPosition.reset();
//            mAnimateToStartPosition.setDuration(duration);
//            mAnimateToStartPosition.setInterpolator(duration == ANIMATE_TO_START_DURATION
//                    ? mDecelerateInterpolator : mLinearInterpolator);
////            mAnimateToStartPosition.setInterpolator(new LinearInterpolator());
//            if (listener != null) {
//                mCircleView.setAnimationListener(listener);
//            }
//            mCircleView.clearAnimation();
//            mCircleView.startAnimation(mAnimateToStartPosition);
//        }
//    }
//    /** 动画矫正child的位置 */
//    private final Animation mAnimateToCorrectPosition = new Animation() {
//        @Override
//        public void applyTransformation(float interpolatedTime, Transformation t) {
//            int targetTop = 0;
//            int endTarget = 0;
//            if (!mUsingCustomStart) {
//                endTarget = mSpinnerOffsetEnd - Math.abs(mOriginalOffsetTop);
//            } else {
//                endTarget = mSpinnerOffsetEnd;
//            }
//            targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
//            int offset = targetTop - mCircleView.getTop();
//            setTargetOffsetTopAndBottom(offset);
////            Log.i("refresh", "偏移量mAnimateToCorrectPosition  offset= "+offset);
////            mProgress.setArrowScale(1 - interpolatedTime);
//        }
//    };
//
//    void moveToStart(float interpolatedTime) {
//        int targetTop = 0;
//        targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
//        int offset = targetTop - mCircleView.getTop();
//        setTargetOffsetTopAndBottom(offset);
////        if (mListener != null) {
////            mListener.onOffset(1- interpolatedTime, true, mFrom);
////            Log.i("refresh", "偏移量tostart  interpolatedTime= "+ interpolatedTime);
////        }
//    }
//
//    private final Animation mAnimateToStartPosition = new Animation() {
//        @Override
//        public void applyTransformation(float interpolatedTime, Transformation t) {
//            moveToStart(interpolatedTime);
//        }
//    };
//
//    private void startScaleDownReturnToStartAnimation(int from,
//                                                      AnimationListener listener) {
//        mFrom = from;
//        mStartingScale = mCircleView.getScaleX();
//        mScaleDownToStartAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                float targetScale = (mStartingScale + (-mStartingScale  * interpolatedTime));
//                setAnimationProgress(targetScale);
//                moveToStart(interpolatedTime);
//            }
//        };
//        mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mScaleDownToStartAnimation);
//    }
//    /** 将mCircleView移到最顶层（父类的Z轴最上层） */
//    void setTargetOffsetTopAndBottom(int offset) {
////        Log.i("refresh", "setTargetOffsetTopAndBottom偏移量 offset= "+offset+"   偏移前的值mCurrentTargetOffsetTop="+mCurrentTargetOffsetTop);
//        mCircleView.bringToFront();
//        ViewCompat.offsetTopAndBottom(mCircleView, offset);
//        mCurrentTargetOffsetTop = mCircleView.getTop();
////        if(offset != 0) Log.i("refresh1", "setTargetOffsetTopAndBottom偏移量不为0   offset= "+offset+"   偏移后的值mCurrentTargetOffsetTop="+mCurrentTargetOffsetTop);
//        if (mListener != null) {
//            mListener.onOffset(offset);
////            Log.i("refresh", "偏移量moving  dragPercent= "+dragPercent+"  targetY="+targetY+"  mCurrentTargetOffsetTop="+mCurrentTargetOffsetTop);
//        }
//    }
//    /** 记录下一根手指id */
//    private void onSecondaryPointerUp(MotionEvent ev) {
//        final int pointerIndex = ev.getActionIndex();
//        final int pointerId = ev.getPointerId(pointerIndex);
//        if (pointerId == mActivePointerId) {
//            // This was our active pointer going up. Choose a new
//            // active pointer and adjust accordingly.
//            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
//            mActivePointerId = ev.getPointerId(newPointerIndex);
//        }
//    }
//
//    /**
//     * Classes that wish to be notified when the swipe gesture correctly
//     * triggers a refresh should implement this interface.
//     */
//    public interface OnRefreshListener {
//        /**
//         * Called when a swipe gesture triggers a refresh.
//         */
//        void onRefresh();
//
//        void onOffset(int offset);
//
//        void onActionUp();
//
//    }
//
//    /**
//     * Classes that wish to override {@link SwipeRefreshLayout#canChildScrollUp()} method
//     * behavior should implement this interface.
//     */
//    public interface OnChildScrollUpCallback {
//        /**
//         * Callback that will be called when {@link SwipeRefreshLayout#canChildScrollUp()} method
//         * is called to allow the implementer to override its behavior.
//         *
//         * @param parent SwipeRefreshLayout that this callback is overriding.
//         * @param child The child view of SwipeRefreshLayout.
//         *
//         * @return Whether it is possible for the child view of parent layout to scroll up.
//         */
//        boolean canChildScrollUp(SwipeRefreshLayout parent, @Nullable View child);
//    }
//}
